package com.ling.ling_push.pusher;

import android.graphics.ImageFormat;
import android.hardware.Camera;
import android.util.Log;
import android.view.Surface;
import android.view.SurfaceHolder;

import com.ling.ling_push.MainActivity;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Iterator;
import java.util.List;

public class CameraHelper implements Camera.PreviewCallback,SurfaceHolder.Callback
{
    //帧率的大小
    private    int  mPreviewHeight;
    private   int  mPreviewWidth;
    //
    private int  cameraId;
    private Camera mCamera;
    private int mWidth=1920,mHeight=1080;
    byte[] buffer,bytes;
    private  Camera.PreviewCallback  mPreviewCallback;
    private SurfaceHolder mSurfaceHolder ;
    private  MainActivity mActivity;

    public CameraHelper(MainActivity activity, int cameraId) {
        mActivity=activity;
        this.cameraId=cameraId;
    }

    /**
     * 开始预览
     */
    String TAG="startPreview";
    public void startPreview() {
            mCamera = Camera.open(cameraId);
            //配置Camera属性
        Camera.Parameters parameters=  mCamera.getParameters();
        // parameters.setFlashMode("off"); // 无闪光灯
        //设置预览数据格式
        parameters.setPreviewFormat(ImageFormat.NV21);
        //设置摄像头宽，高
        setPreviewSice(parameters);
        setPreviewOrieentation(parameters);
        parameters.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_VIDEO);
        mCamera.setParameters(parameters);
           // buffers = new byte[videoParams.getWidth() * videoParams.getHeight() * 3/4];
            //buffer=new byte[1920*1080*3/2];
            //数据缓冲区
            buffer =new byte[mPreviewWidth*mPreviewHeight*3/2];
            bytes =new byte[buffer.length];
            //数据回调接口
            mCamera.addCallbackBuffer(buffer);
            mCamera.setPreviewCallbackWithBuffer(this);
            //设置摄像头属性
        try {
           mCamera.setPreviewDisplay(mSurfaceHolder);
        } catch (IOException e) {
            e.printStackTrace();
        }
        mCamera.startPreview();
        // 【调试】设置后的图片大小和预览大小以及帧率打印出来
        Camera.Size csize = mCamera.getParameters().getPreviewSize();//帧率的大小
          mPreviewHeight = csize.height;
          mPreviewWidth = csize.width;
        Log.i(TAG+"initCamera", "after setting, previewSize:width: " + csize.width + " height: " + csize.height);
        csize = mCamera.getParameters().getPictureSize();//图片的大小
        Log.i(TAG+"initCamera", "after setting, pictruesize:width: " + csize.width + " height: " + csize.height);
        Log.i(TAG+"initCamera", "after setting, previewformate is " + mCamera.getParameters().getPreviewFormat());
        Log.i(TAG+"initCamera", "after setting, previewframetate is " + mCamera.getParameters().getPreviewFrameRate());
    }
    private void setPreviewOrieentation(Camera.Parameters paramet) {
        Camera.CameraInfo info =
                new Camera.CameraInfo();
        Camera.getCameraInfo(cameraId, info);
        int rotation = mActivity.getWindowManager().getDefaultDisplay()
                .getRotation();
        int degrees = 0;
        switch (rotation) {
            case Surface.ROTATION_0: degrees = 0; break;
            case Surface.ROTATION_90: degrees = 90; break;
            case Surface.ROTATION_180: degrees = 180; break;
            case Surface.ROTATION_270: degrees = 270; break;
        }

        int result;
        if (info.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) {
            result = (info.orientation + degrees) % 360;
            result = (360 - result) % 360;  // compensate the mirror
        } else {  // back-facing
            result = (info.orientation - degrees + 360) % 360;
        }
        mCamera.setDisplayOrientation(result);
    }

    private void setPreviewSice(Camera.Parameters parameters) {
        //获取摄像头支持的宽，高
        List<Camera.Size> supportedPreviewSizes=parameters.getSupportedPreviewSizes();
        Camera.Size size=supportedPreviewSizes.get(0);
        Log.d("setPreviewSice","支持"+size.width+"X"+size.height);
        //选择一个最小的支持分辨率
        int m=Math.abs(size.height*size.width-mWidth*mHeight);
        supportedPreviewSizes.remove(0);
        Iterator<Camera.Size> iterator=supportedPreviewSizes.iterator();
        while (iterator.hasNext()){
            Camera.Size next=iterator.next();
            Log.d("setPreviewSice","支持"+size.width+"X"+size.height);
            int n=Math.abs(next.height*next.width-mWidth*mHeight);
            if (n<m){
                m=n;
                size=next;
            }
        }
        mWidth=size.width;
        mHeight=size.height;
        parameters.setPreviewSize(mWidth,mHeight);
        Log.d("setPreviewSice","设置分辨率：width"+size.width+"height"+size.height);
    }
    public void setPreviewCallback(Camera.PreviewCallback previewCallback) {
        mPreviewCallback=previewCallback;
    }
    @Override
    public void onPreviewFrame(byte[] data, Camera camera) {
        if (mPreviewCallback!=null){
            mPreviewCallback.onPreviewFrame(data,camera);

        }
        camera.addCallbackBuffer(bytes);
    }

    public int getCameraId() {
        return cameraId;
    }
    public void setCameraId(int cameraId) {
        this.cameraId = cameraId;
    }

    public int getmPreviewHeight() {
        return mPreviewHeight;
    }

    public int getmPreviewWidth() {
        return mPreviewWidth;
    }
    /**
     * 停止预览
     */
    public void stopPreview() {
        if(mCamera != null){
            mCamera.setPreviewCallback(null);
            mCamera.stopPreview();
            mCamera.release();
            mCamera = null;
        }
    }
    /**
     * 切换摄像头
     */
    public void switchCamera() {
        if( cameraId== Camera.CameraInfo.CAMERA_FACING_BACK){
           setCameraId(Camera.CameraInfo.CAMERA_FACING_FRONT);
        }else{
            setCameraId(Camera.CameraInfo.CAMERA_FACING_BACK);
        }
        //重新预览
        stopPreview();
       startPreview();
    }
    public void setSurfaceHolder(SurfaceHolder mSurfaceHolder) {
        this.mSurfaceHolder = mSurfaceHolder;
        this.mSurfaceHolder.addCallback(this);
    }
    SurfaceHolder s;
    @Override
    public void surfaceCreated(SurfaceHolder surfaceHolder) {
    }

    @Override
    public void surfaceChanged(SurfaceHolder surfaceHolder, int i, int i1, int i2) {
        stopPreview();
        startPreview();
    }

    @Override
    public void surfaceDestroyed(SurfaceHolder surfaceHolder) {
        startPreview();
    }

//--------------------------------------------------------
    // 这里反过来是因为相机的分辨率跟屏幕的分辨率宽高刚好反过来
    public final float Ratio_4_3 = 0.75f;
    public final float Ratio_1_1 = 1.0f;
    public final float Ratio_16_9 = 0.5625f;
    // 当前的宽高比
    private float mCurrentRatio = Ratio_16_9;
    /**
     * 设置预览大小
     * @param camera
     * @param expectWidth
     * @param expectHeight
     */
    private void setPreviewSize(Camera camera, int expectWidth, int expectHeight) {
        Camera.Parameters parameters = camera.getParameters();
        Camera.Size size = calculatePerfectSize(parameters.getSupportedPreviewSizes(),
                expectWidth, expectHeight);
        parameters.setPreviewSize(size.width, size.height);
        camera.setParameters(parameters);
        Log.d("setPreviewSize", "width = " + size.width + ", height = " + size.height);
    }
    /**
     * 设置拍摄的照片大小
     * @param camera
     * @param expectWidth
     * @param expectHeight
     */
    private void setPictureSize(Camera camera, int expectWidth, int expectHeight) {
        Camera.Parameters parameters = camera.getParameters();
        Camera.Size size = calculatePerfectSize(parameters.getSupportedPictureSizes(),
                expectWidth, expectHeight);
        parameters.setPictureSize(size.width, size.height);
        camera.setParameters(parameters);
        Log.d("setPictureSize", "width = " + size.width + ", height = " + size.height);
    }
    /**
     * 计算最完美的Size
     * @param sizes
     * @param expectWidth
     * @param expectHeight
     * @return
     */
    private Camera.Size calculatePerfectSize(List<Camera.Size> sizes, int expectWidth,
                                             int expectHeight) {
        sortList(sizes); // 根据宽度进行排序

        // 根据当前期望的宽高判定
        List<Camera.Size> bigEnough = new ArrayList<>();
        List<Camera.Size> noBigEnough = new ArrayList<>();
        for (Camera.Size size : sizes) {
            if (size.height * expectWidth / expectHeight == size.width) {
                if (size.width >= expectWidth && size.height >= expectHeight) {
                    bigEnough.add(size);
                } else {
                    noBigEnough.add(size);
                }
            }
        }
        if (bigEnough.size() > 0) {
            return Collections.min(bigEnough, new CompareAreaSize());
        } else if (noBigEnough.size() > 0) {
            return Collections.max(noBigEnough, new CompareAreaSize());
        } else { // 如果不存在满足要求的数值，则辗转计算宽高最接近的值
            Camera.Size result = sizes.get(0);
            boolean widthOrHeight = false; // 判断存在宽或高相等的Size
            // 辗转计算宽高最接近的值
            for (Camera.Size size : sizes) {
                // 如果宽高相等，则直接返回
                if (size.width == expectWidth && size.height == expectHeight
                        && ((float) size.height / (float) size.width) == mCurrentRatio) {
                    result = size;
                    break;
                }
                // 仅仅是宽度相等，计算高度最接近的size
                if (size.width == expectWidth) {
                    widthOrHeight = true;
                    if (Math.abs(result.height - expectHeight)
                            > Math.abs(size.height - expectHeight)
                            && ((float) size.height / (float) size.width) == mCurrentRatio) {
                        result = size;
                        break;
                    }
                }
                // 高度相等，则计算宽度最接近的Size
                else if (size.height == expectHeight) {
                    widthOrHeight = true;
                    if (Math.abs(result.width - expectWidth)
                            > Math.abs(size.width - expectWidth)
                            && ((float) size.height / (float) size.width) == mCurrentRatio) {
                        result = size;
                        break;
                    }
                }
                // 如果之前的查找不存在宽或高相等的情况，则计算宽度和高度都最接近的期望值的Size
                else if (!widthOrHeight) {
                    if (Math.abs(result.width - expectWidth)
                            > Math.abs(size.width - expectWidth)
                            && Math.abs(result.height - expectHeight)
                            > Math.abs(size.height - expectHeight)
                            && ((float) size.height / (float) size.width) == mCurrentRatio) {
                        result = size;
                    }
                }
            }
            return result;
        }
    }

    /**
     * 分辨率由大到小排序
     * @param list
     */
    private void sortList(List<Camera.Size> list) {
        Collections.sort(list, new CompareAreaSize());
    }

    /**
     * 比较器
     */
    private class CompareAreaSize implements Comparator<Camera.Size> {
        @Override
        public int compare(Camera.Size pre, Camera.Size after) {
            return Long.signum((long) pre.width * pre.height -
                    (long) after.width * after.height);
        }
    }

    /**
     * 选择合适的FPS
     * @param parameters
     * @param expectedThoudandFps 期望的FPS
     * @return
     */
    private int chooseFixedPreviewFps(Camera.Parameters parameters, int expectedThoudandFps) {
        List<int[]> supportedFps = parameters.getSupportedPreviewFpsRange();
        for (int[] entry : supportedFps) {
            if (entry[0] == entry[1] && entry[0] == expectedThoudandFps) {
                parameters.setPreviewFpsRange(entry[0], entry[1]);
                return entry[0];
            }
        }
        int[] temp = new int[2];
        int guess;
        parameters.getPreviewFpsRange(temp);
        if (temp[0] == temp[1]) {
            guess = temp[0];
        } else {
            guess = temp[1] / 2;
        }
        return guess;
    }
}
